#include <util/delay.h>
#include <avr/io.h>
#include "I2c.h"

//-------------------------------------------------------------
// Port for the I2C
#define I2C_DDR DDRD
#define I2C_PIN PIND
#define I2C_PORT PORTD

// Pins to be used in the bit banging
#define I2C_CLK 0    
#define I2C_DAT 1

//#define I2C_DELAY()
#define I2C_DELAY() _delay_us(1);
//#define I2C_DELAY() _delay_ms(1);

#define I2C_IS_CLOCK_HI() ( (I2C_PIN >> I2C_CLK ) & 1 )

#define I2C_DATA_HI() { I2C_DDR &= ~( 1 << I2C_DAT );  }
#define I2C_DATA_LO() { I2C_DDR |=  ( 1 << I2C_DAT );  }

#define I2C_CLOCK_HI() { I2C_DDR &= ~( 1 << I2C_CLK ); I2C_DELAY();  }
#define I2C_CLOCK_LO() { I2C_DDR |=  ( 1 << I2C_CLK ); I2C_DELAY();  }


// Inits bitbanging port, must be called before using the functions below
//
void I2C_Init()
{
    TWCR = 0;

	I2C_PORT &= ~( ( 1 << I2C_DAT ) | ( 1 << I2C_CLK ) );

	I2C_DATA_HI();
	I2C_CLOCK_HI();

	for( char i = 0;i<3;i++)
	{
		I2C_Start();
		I2C_Stop();
	}

	_delay_ms(1);
}

// Send a START Condition
//
void I2C_Start()
{

	I2C_DATA_HI();
	I2C_CLOCK_HI();
	
	// set both to high at the same time
	I2C_DATA_LO();
	I2C_DELAY();

	I2C_CLOCK_LO();
}


// Send a STOP Condition
//
void I2C_Stop()
{
	I2C_CLOCK_HI();

	I2C_DATA_HI();
	I2C_DELAY();
}


unsigned char I2C_GetAck()
{
	I2C_DATA_HI();

	I2C_CLOCK_HI();

	unsigned char c = ( (I2C_PIN >> I2C_DAT ) & 1);

	I2C_CLOCK_LO();

	return c==0;
}


// write a byte to the I2C slave device
//
unsigned char I2C_Write( unsigned char data )
{
	for ( char i=0;i<8;i++)
	{
		if ( data & 128 )
		{
			I2C_DATA_HI();
		}
		else
		{
			I2C_DATA_LO();
		}
		//I2C_DELAY();

		I2C_CLOCK_HI();


		I2C_CLOCK_LO();


		data <<= 1;
	}

	return I2C_GetAck();
}


// read a byte from the I2C slave device
//
unsigned char I2C_Read( unsigned char ackFlag )
{
	unsigned char res = 0;

	I2C_DATA_HI();

	for ( char i=0;i<8;i++)
	{
		res <<= 1;

		I2C_CLOCK_HI();


		res |= ( I2C_PIN >> I2C_DAT ) & 1; 

		I2C_CLOCK_LO();
	}

	if (ackFlag>0)
	{
		I2C_DATA_LO();
	}


	I2C_CLOCK_HI();


	I2C_CLOCK_LO();



	return res;
}



